今天要介紹的是 .NET Core 的 Log,會介紹 Log 是因為 LineBot 不能在本機 Debug,需要直接在 Azure 排除錯誤,為了解決這個問題自己花了很多時間研究,過程中發現相關的文章不多,所以才想獨立寫一篇和大家分享。
因為 .NET Core 原生的 Log 只能輸出到 Console 視窗,所以這邊會配合 NLog 套件改為輸出成檔案,這就開始吧。
需要安裝的套件 (Nuget)
1. 新增 nlog.config
在根目錄下新增 nlog.config 檔案。
參考文章: https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-3
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Info"
internalLogFile="D:\home\site\AspNetCoreNlog\Logs\internal-nlog.txt">
<extensions>
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
<targets>
<target xsi:type="File" name="allfile" fileName="D:\home\site\AspNetCoreNlog\Logs\all\nlog-all-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />
<target xsi:type="File" name="ownFile-web" fileName="D:\home\site\AspNetCoreNlog\Logs\own\nlog-own-${shortdate}.log"
layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="allfile" />
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
</nlog>
修改輸出路徑 internalLogFile
和 fileName
,我會將 Log 輸出到 D:\home\site
的 AspNetCoreNlog 目錄下。
internalLogFile="D:\home\site\AspNetCoreNlog\Logs\internal-nlog.txt"
fileName="D:\home\site\AspNetCoreNlog\Logs\all\nlog-all-${shortdate}.log"
fileName="D:\home\site\AspNetCoreNlog\Logs\own\nlog-own-${shortdate}.log"
2. 開啟 nlog.config 的 屬性視窗
將 複製到輸出目錄
改為 永遠複製
。
3. 調整 Program.cs 加入 NLog。
.UseNLog()
完整的 Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseNLog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
4. 在 LineBotController 的建構式內透過 DI 注入 ILogger。
private readonly ILogger _logger;
public LineBotController(
...
ILogger<LineBotController> logger)
{
...
_logger = logger;
}
故意讓程式出錯,發行後測試一下。
try
{
throw new Exception("出錯了~出錯了~");
...
}
catch (Exception ex)
{
_logger.LogError(JsonConvert.SerializeObject(ex));
}
完整 LineBotController 程式
[Route("api/linebot")]
public class LineBotController : Controller
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly HttpContext _httpContext;
private readonly LineBotConfig _lineBotConfig;
private readonly ILogger _logger;
public LineBotController(IServiceProvider serviceProvider,
LineBotConfig lineBotConfig,
ILogger<LineBotController> logger)
{
_httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
_httpContext = _httpContextAccessor.HttpContext;
_lineBotConfig = lineBotConfig;
_logger = logger;
}
[HttpPost("run")]
public async Task<IActionResult> Post()
{
try
{
throw new Exception("出錯了~出錯了~");
var events = await _httpContext.Request.GetWebhookEventsAsync(_lineBotConfig.channelSecret);
var lineMessagingClient = new LineMessagingClient(_lineBotConfig.accessToken);
var lineBotApp = new LineBotApp(lineMessagingClient);
await lineBotApp.RunAsync(events);
}
catch (Exception ex)
{
_logger.LogError(JsonConvert.SerializeObject(ex));
}
return Ok();
}
}
接下來要介紹哪裡可以看 Log,這是我亂點功能時發現的。
開啟 App Service 管理介面,在左邊選單找到 進階工具
,點開選執行。
接下來找到上方選單 Debug console
然後選 PowerShell
就可以看到這個畫面。
到這裡大家應該知道怎麼找了,上面有透漏 Log 的存放路徑。
D:\home\site\AspNetCoreNlog\Logs
開啟目錄 all 或 own 都可以,差別是顯示的格式不同,進入目錄後可以看到 Log 會依日期分割檔案,開啟今天日期的檔案後,可以看到測試的錯誤訊息 出錯了~出錯了~
。
到這裡查 Log 的部分已經完成,以下為碎碎念,可以不要理我 ~~~
預設存放 log 的路徑其實是根目錄 wwwroot,我本來也想放在這裡,不過 Azure 新的部屬方式會將 wwwroot 變成唯讀的,導致 Log 寫入失敗,退而求其次才修改了 Log 的路徑,相關說明: 從套件檔案執行 Azure Functions。
修改 wwwroot 內的檔案會出現下面錯誤訊息。
409 Conflict: Cannot delete directory. It is either not empty or access is not allowed.
雖然可以透過修改 組態
參數 WEBSITE_RUN_FROM_PACKAGE=0
暫時將 wwwroot 改為可讀寫,不過資料夾內的檔案會被全部刪除,且重新發行後參數又會被改回去,因此這個解決方案顯然行不通。
繼續研究找到這篇文章: Write operations to any file under wwwroot folder fails with 409 conflict when using Azure DevOps pipeline.
發現可以將 Pipelines 的部屬方式由 Zip Deploy
改成 Web Deploy
這樣就能像以前一樣正常讀寫 wwwroot 資料夾。
到 Azure DevOps 管理頁面,進入 Releases
選單,點選右上角的 Edit
。
接著選擇 Tasks 選項,會看到下列畫面,發現和文章中的不太一樣,文章中使用的是 Azure App Service deploy
而我的是 Azure Web App
且部屬選項不能選擇 Web Deploy,到這裡我想就算了,新的部屬方式也有其優點,wwwroot 唯讀就唯讀吧,所以就把 log 拉到外層,心路歷程是這樣,哈哈哈。
下面留給追求完美的人看,將原 Azure Web App
刪除,新增 Azure App Service deploy
將部屬方式改為傳統的 Web Deploy
。
我把兩邊的配置都留下,大家選自己喜歡的用吧。
最後介紹一個好用的功能,App Service 編輯器
可以線上修改文件和查看相關設定檔,不過只限於 wwwroot 資料夾。
在 App Service 管理頁面找到 App Service 編輯器選單,進入後點執行。
介面如下。
這篇介紹了 NLog 和在 Azure 上設定 Log 會碰到的一些問題,本來想和 MySQL 一起寫,後來想想還是留到後面好了,還沒想好 LineBot 要做的功能,沒辦法開資料表,下一篇會介紹 LUIS 語意分析服務,今天就到這裡,感謝大家觀看。
這篇困難重重,滿滿的坑 QQ......
將 ASP.NET Core 的預設 log 輸出至 NLog 或 Serilog